home *** CD-ROM | disk | FTP | other *** search
/ Aminet 41 / Aminet 41 (2001)(Schatztruhe)[!][Feb 2001].iso / Aminet / misc / sci / Denise4_2.lha / Denise4_2 / source / include / simplerexx.c < prev    next >
C/C++ Source or Header  |  1980-01-06  |  10KB  |  423 lines

  1. /*
  2.  * Simple ARexx interface...
  3.  *
  4.  * This is a very "Simple" interface to the world of ARexx...
  5.  * For more complex interfaces into ARexx, it is best that you
  6.  * understand the functions that are provided by ARexx.
  7.  * In many cases they are more powerful than what is presented
  8.  * here.
  9.  *
  10.  * This code is fully re-entrant and self-contained other than
  11.  * the use of SysBase/AbsExecBase and the ARexx RVI support
  12.  * library which is also self-contained...
  13.  */
  14.  
  15. #include    <exec/types.h>
  16. #include    <exec/nodes.h>
  17. #include    <exec/lists.h>
  18. #include    <exec/ports.h>
  19. #include    <exec/memory.h>
  20.  
  21. #include    <clib/alib_protos.h>
  22. #include    <clib/exec_protos.h>
  23. #include    <clib/dos_protos.h>
  24.  
  25. #include    <rexx/storage.h>
  26. #include    <rexx/rxslib.h>
  27.  
  28. #include    <string.h>
  29. #include    <ctype.h>
  30.  
  31. /*
  32.  * The prototypes for the few ARexx functions we will call...
  33.  */
  34. struct RexxMsg *CreateRexxMsg(struct MsgPort *,char *,char *);
  35. void *CreateArgstring(char *,long);
  36. void DeleteRexxMsg(struct RexxMsg *);
  37. void DeleteArgstring(char *);
  38. BOOL IsRexxMsg(struct Message *);
  39.  
  40. /*
  41.  * Pragmas for the above functions...  (To make this all self-contained...)
  42.  * If you use RexxGlue.o, this is not needed...
  43.  *
  44.  * These are for Lattice C 5.x  (Note the use of RexxContext->RexxSysBase)
  45.  */
  46. #pragma libcall RexxContext->RexxSysBase CreateRexxMsg 90 09803
  47. #pragma libcall RexxContext->RexxSysBase CreateArgstring 7E 0802
  48. #pragma libcall RexxContext->RexxSysBase DeleteRexxMsg 96 801
  49. #pragma libcall RexxContext->RexxSysBase DeleteArgstring 84 801
  50. #pragma libcall RexxContext->RexxSysBase IsRexxMsg A8 801
  51.  
  52. /*
  53.  * Prototypes for the RVI ARexx calls...  (link with RexxVars.o)
  54.  */
  55. /*
  56. __stdargs long CheckRexxMsg(struct RexxMsg *);
  57. __stdargs long GetRexxVar(struct RexxMsg *,char *,char **);
  58. __stdargs long SetRexxVar(struct RexxMsg *,char *,char *,long);
  59. */
  60. /*
  61.  * Now, we have made the pragmas needed, let's get to work...
  62.  */
  63.  
  64. /*
  65.  * A structure for the ARexx handler context
  66.  * This is *VERY* *PRIVATE* and should not be touched...
  67.  */
  68. struct    ARexxContext
  69. {
  70. struct    MsgPort    *ARexxPort;    /* The port messages come in at... */
  71. struct    Library    *RexxSysBase;    /* We will hide the library pointer here... */
  72.     long    Outstanding;    /* The count of outstanding ARexx messages... */
  73.     char    PortName[24];    /* The port name goes here... */
  74.     char    ErrorName[28];    /* The name of the <base>.LASTERROR... */
  75.     char    Extension[8];    /* Default file name extension... */
  76. };
  77.  
  78. #define    AREXXCONTEXT    struct ARexxContext *
  79.  
  80. #include    "SimpleRexx.h"
  81.  
  82. /*
  83.  * This function returns the port name of your ARexx port.
  84.  * It will return NULL if there is no ARexx port...
  85.  *
  86.  * This string is *READ ONLY*  You *MUST NOT* modify it...
  87.  */
  88. char *ARexxName(AREXXCONTEXT RexxContext)
  89. {
  90. register    char    *tmp=NULL;
  91.  
  92.     if (RexxContext) tmp=RexxContext->PortName;
  93.     return(tmp);
  94. }
  95.  
  96. /*
  97.  * This function returns the signal mask that the Rexx port is
  98.  * using.  It returns NULL if there is no signal...
  99.  *
  100.  * Use this signal bit in your Wait() loop...
  101.  */
  102. ULONG ARexxSignal(AREXXCONTEXT RexxContext)
  103. {
  104. register    ULONG    tmp=NULL;
  105.  
  106.     if (RexxContext) tmp=1L << (RexxContext->ARexxPort->mp_SigBit);
  107.     return(tmp);
  108. }
  109.  
  110. /*
  111.  * This function returns a structure that contains the commands sent from
  112.  * ARexx...  You will need to parse it and return the structure back
  113.  * so that the memory can be freed...
  114.  *
  115.  * This returns NULL if there was no message...
  116.  */
  117. struct RexxMsg *GetARexxMsg(AREXXCONTEXT RexxContext)
  118. {
  119. register    struct    RexxMsg    *tmp=NULL;
  120. register        short    flag;
  121.  
  122.     if (RexxContext)
  123.         if (tmp=(struct RexxMsg *)GetMsg(RexxContext->ARexxPort))
  124.     {
  125.         if (tmp->rm_Node.mn_Node.ln_Type==NT_REPLYMSG)
  126.         {
  127.             /*
  128.              * If we had sent a command, it would come this way...
  129.              *
  130.              * Since we don't in this simple example, we just throw
  131.              * away anything that looks "strange"
  132.              */
  133.             flag=FALSE;
  134.             if (tmp->rm_Result1) flag=TRUE;
  135.  
  136.             /*
  137.              * Free the arguments and the message...
  138.              */
  139.             DeleteArgstring(tmp->rm_Args[0]);
  140.             DeleteRexxMsg(tmp);
  141.             RexxContext->Outstanding-=1;
  142.  
  143.             /*
  144.              * Return the error if there was one...
  145.              */
  146.             tmp=flag ? REXX_RETURN_ERROR : NULL;
  147.         }
  148.     }
  149.     return(tmp);
  150. }
  151.  
  152. /*
  153.  * Use this to return a ARexx message...
  154.  *
  155.  * If you wish to return something, it must be in the RString.
  156.  * If you wish to return an Error, it must be in the Error.
  157.  * If there is an error, the RString is ignored.
  158.  */
  159. void ReplyARexxMsg(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  160.             char *RString,LONG Error)
  161. {
  162.     if (RexxContext) if (rmsg) if (rmsg!=REXX_RETURN_ERROR)
  163.     {
  164.         rmsg->rm_Result2=0;
  165.         if (!(rmsg->rm_Result1=Error))
  166.         {
  167.             /*
  168.              * if you did not have an error we return the string
  169.              */
  170.             if (rmsg->rm_Action & (1L << RXFB_RESULT)) if (RString)
  171.             {
  172.                 rmsg->rm_Result2=(LONG)CreateArgstring(RString,
  173.                             (LONG)strlen(RString));
  174.             }
  175.         }
  176.  
  177.         /*
  178.          * Reply the message to ARexx...
  179.          */
  180.         ReplyMsg((struct Message *)rmsg);
  181.     }
  182. }
  183.  
  184. /*
  185.  * This function will set an error string for the ARexx
  186.  * application in the variable defined as <appname>.LASTERROR
  187.  *
  188.  * Note that this can only happen if there is an ARexx message...
  189.  *
  190.  * This returns TRUE if it worked, FALSE if it did not...
  191.  */
  192. short SetARexxLastError(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  193.             char *ErrorString)
  194. {
  195. register    short    OkFlag=FALSE;
  196.  
  197.     if (RexxContext) if (rmsg) if (CheckRexxMsg(rmsg))
  198.     {
  199.         /*
  200.          * Note that SetRexxVar() has more than just a TRUE/FALSE
  201.          * return code, but for this "basic" case, we just care if
  202.          * it works or not.
  203.          */
  204.         if (!SetRexxVar(rmsg,RexxContext->ErrorName,ErrorString,
  205.                         (long)strlen(ErrorString)))
  206.         {
  207.             OkFlag=TRUE;
  208.         }
  209.     }
  210.     return(OkFlag);
  211. }
  212.  
  213. /*
  214.  * This function will send a string to ARexx...
  215.  *
  216.  * The default host port will be that of your task...
  217.  *
  218.  * If you set StringFile to TRUE, it will set that bit for the message...
  219.  *
  220.  * Returns TRUE if it send the message, FALSE if it did not...
  221.  */
  222. short SendARexxMsg(AREXXCONTEXT RexxContext,char *RString,
  223.             short StringFile)
  224. {
  225. register    struct    MsgPort    *RexxPort;
  226. register    struct    RexxMsg    *rmsg;
  227. register        short    flag=FALSE;
  228.  
  229.     if (RexxContext) if (RString)
  230.     {
  231.         if (rmsg=CreateRexxMsg(RexxContext->ARexxPort,
  232.                     RexxContext->Extension,
  233.                     RexxContext->PortName))
  234.         {
  235.             rmsg->rm_Action=RXCOMM | (StringFile ?
  236.                             (1L << RXFB_STRING):0);
  237.             if (rmsg->rm_Args[0]=CreateArgstring(RString,
  238.                             (LONG)strlen(RString)))
  239.             {
  240.                 /*
  241.                  * We need to find the RexxPort and this needs
  242.                  * to be done in a Forbid()
  243.                  */
  244.                 Forbid();
  245.                 if (RexxPort=FindPort(RXSDIR))
  246.                 {
  247.                     /*
  248.                      * We found the port, so put the
  249.                      * message to ARexx...
  250.                      */
  251.                     PutMsg(RexxPort,(struct Message *)rmsg);
  252.                     RexxContext->Outstanding+=1;
  253.                     flag=TRUE;
  254.                 }
  255.                 else
  256.                 {
  257.                     /*
  258.                      * No port, so clean up...
  259.                      */
  260.                     DeleteArgstring(rmsg->rm_Args[0]);
  261.                     DeleteRexxMsg(rmsg);
  262.                 }
  263.                 Permit();
  264.             }
  265.             else DeleteRexxMsg(rmsg);
  266.         }
  267.     }
  268.     return(flag);
  269. }
  270.  
  271. /*
  272.  * This function closes down the ARexx context that was opened
  273.  * with InitARexx...
  274.  */
  275. void FreeARexx(AREXXCONTEXT RexxContext)
  276. {
  277. register    struct    RexxMsg    *rmsg;
  278.  
  279.     if (RexxContext)
  280.     {
  281.         /*
  282.          * Clear port name so it can't be found...
  283.          */
  284.         RexxContext->PortName[0]='\0';
  285.  
  286.         /*
  287.          * Clean out any outstanding messages we had sent out...
  288.          */
  289.         while (RexxContext->Outstanding)
  290.         {
  291.             WaitPort(RexxContext->ARexxPort);
  292.             while (rmsg=GetARexxMsg(RexxContext))
  293.             {
  294.                 if (rmsg!=REXX_RETURN_ERROR)
  295.                 {
  296.                     /*
  297.                      * Any messages that come now are blown
  298.                      * away...
  299.                      */
  300.                     SetARexxLastError(RexxContext,rmsg,
  301.                                 "99: Port Closed!");
  302.                     ReplyARexxMsg(RexxContext,rmsg,
  303.                             NULL,100);
  304.                 }
  305.             }
  306.         }
  307.  
  308.         /*
  309.          * Clean up the port and delete it...
  310.          */
  311.         if (RexxContext->ARexxPort)
  312.         {
  313.             while (rmsg=GetARexxMsg(RexxContext))
  314.             {
  315.                 /*
  316.                  * Any messages that still are coming in are
  317.                  * "dead"  We just set the LASTERROR and
  318.                  * reply an error of 100...
  319.                  */
  320.                 SetARexxLastError(RexxContext,rmsg,
  321.                             "99: Port Closed!");
  322.                 ReplyARexxMsg(RexxContext,rmsg,NULL,100);
  323.             }
  324.             DeletePort(RexxContext->ARexxPort);
  325.         }
  326.  
  327.         /*
  328.          * Make sure we close the library...
  329.          */
  330.         if (RexxContext->RexxSysBase)
  331.         {
  332.             CloseLibrary(RexxContext->RexxSysBase);
  333.         }
  334.  
  335.         /*
  336.          * Free the memory of the RexxContext
  337.          */
  338.         FreeMem(RexxContext,sizeof(struct ARexxContext));
  339.     }
  340. }
  341.  
  342. /*
  343.  * This routine initializes an ARexx port for your process
  344.  * This should only be done once per process.  You must call it
  345.  * with a valid application name and you must use the handle it
  346.  * returns in all other calls...
  347.  *
  348.  * NOTE:  The AppName should not have spaces in it...
  349.  *        Example AppNames:  "MyWord" or "FastCalc" etc...
  350.  *        The name *MUST* be less that 16 characters...
  351.  *        If it is not, it will be trimmed...
  352.  *        The name will also be UPPER-CASED...
  353.  *
  354.  * NOTE:  The Default file name extension, if NULL will be
  355.  *        "rexx"  (the "." is automatic)
  356.  */
  357. AREXXCONTEXT InitARexx(char *AppName,char *Extension)
  358. {
  359. register    AREXXCONTEXT    RexxContext=NULL;
  360. register    short        loop;
  361. register    short        count;
  362. register    char        *tmp;
  363.  
  364.     if (RexxContext=AllocMem(sizeof(struct ARexxContext),
  365.                     MEMF_PUBLIC|MEMF_CLEAR))
  366.     {
  367.         if (RexxContext->RexxSysBase=OpenLibrary("rexxsyslib.library",
  368.                                 NULL))
  369.         {
  370.             /*
  371.              * Set up the extension...
  372.              */
  373.             if (!Extension) Extension="rexx";
  374.             tmp=RexxContext->Extension;
  375.             for (loop=0;(loop<7)&&(Extension[loop]);loop++)
  376.             {
  377.                 *tmp++=Extension[loop];
  378.             }
  379.             *tmp='\0';
  380.  
  381.             /*
  382.              * Set up a port name...
  383.              */
  384.             tmp=RexxContext->PortName;
  385.             for (loop=0;(loop<16)&&(AppName[loop]);loop++)
  386.             {
  387.                 *tmp++=toupper(AppName[loop]);
  388.             }
  389.             *tmp='\0';
  390.  
  391.             /*
  392.              * Set up the last error RVI name...
  393.              *
  394.              * This is <appname>.LASTERROR
  395.              */
  396.             strcpy(RexxContext->ErrorName,RexxContext->PortName);
  397.             strcat(RexxContext->ErrorName,".LASTERROR");
  398.  
  399.             /* We need to make a unique port name... */
  400.             Forbid();
  401.             for (count=1,RexxContext->ARexxPort=(VOID *)1;
  402.                         RexxContext->ARexxPort;count++)
  403.             {
  404.                 stci_d(tmp,count);
  405.                 RexxContext->ARexxPort=
  406.                         FindPort(RexxContext->PortName);
  407.             }
  408.  
  409.             RexxContext->ARexxPort=CreatePort(
  410.                         RexxContext->PortName,NULL);
  411.             Permit();
  412.         }
  413.  
  414.         if (    (!(RexxContext->RexxSysBase))
  415.              ||    (!(RexxContext->ARexxPort))    )
  416.         {
  417.             FreeARexx(RexxContext);
  418.             RexxContext=NULL;
  419.         }
  420.     }
  421.     return(RexxContext);
  422. }
  423.